/**
 * 
 * 
 *  
 *====================================================
 * 文件名称: BaseAction.java
 * 修订记录：
 * No    日期				作者(操作:具体内容)
 * 1.    2008-7-3			
 *====================================================
 * 类描述：(说明未实现或其它不应生成javadoc的内容)
 * 
 */
package com.devframe.web;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.ValidatorForm;

import com.devframe.sys.util.page.PageInfo;
import com.devframe.sysconfig.storage.operate.ReaderCacheData;
import com.devframe.web.interceptors.InterceptAble;
import com.devframe.web.interceptors.MyInterceptorStack;
import com.devframe.web.loader.MyWebContextLoader;

/**
 * <pre>
 * &lt;b&gt;&lt;font color=&quot;blue&quot;&gt;BaseAction&lt;/font&gt;&lt;/b&gt;
 * </pre>
 * 
 * <pre>
 * &lt;b&gt; --描述说明--&lt;/b&gt;
 * </pre>
 * <pre></pre>
 * <pre>
 * &lt;b&gt;--样例--&lt;/b&gt;
 *   BaseAction obj = new BaseAction();
 *   obj.method();
 * </pre>
 * 
 * JDK版本：JDK1.4
 * 
 * 
 */
public class Struts1BaseAction extends ValidatorForm implements MyAction,InterceptAble {
	
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1727840077597900499L;

    /**
     * logger，日志输出，可以由子类使用。
     */
    protected Logger logger = Logger.getLogger(getClass());

    /**
     * context 上下文对象，由框架注入。不绑定web环境，方便测试。
     */
    protected MyContext context;

    /**
     * pageInfo 分页数据交互对象
     */
    protected PageInfo pageInfo = new PageInfo();

    /**
     * actionErrors存放特定错误信息，可以多个，用于存放字段级错误信息。
     */
    private Map actionErrors = new LinkedHashMap();

    /**
     * interceptorStack 拦截栈，可配置
     */
    private MyInterceptorStack interceptorStack;

    /**
     * actionError 普通错误信息
     */
    private String actionError;
    
    
    private ReaderCacheData readerCacheData;

 
	
    /**
     * 返回成功操作信息
     * @param message 操作信息
     * @param data 返回数据
     * @return 成功操作信息
     */
	public Map getSuccessResult(String message){
	    return getSuccessResult(message,null);
	}
	/**
	 * 返回成功操作信息
	 * @param message 操作信息
	 * @param data 返回数据
	 * @return 成功操作信息
	 */
	public Map getSuccessResult(String message,Object data){
		Map result = new HashMap();
		result.put(MyAction.STATUS, MyAction.SUCCESS);
		if(message!=null){
	        result.put(MyAction.MESSAGE, message);
		}
		if(data!=null){
		    result.put(MyAction.DATA,data);
		}
		return result;
	}
    /**
     * 仅返回成功状态，前台不提示
     * getSuccessResult
     * @return AJAX成功信息
     */
    public Map getSuccessResult(){
        return getSuccessResult(null,null);
    }
	/**
	 * 仅返回成功状态和数据，前台不提示消息
	 * getSuccessResult
	 * @return AJAX成功信息
	 */
	public Map getSuccessResult(Object data){
        return getSuccessResult(null,data);
	}
	
	/**
	 * 返回失败操作信息
	 * @param message 信息内容
	 * @return 失败操作信息
	 */
	public Map getErrorResult(String message){
		Map result = new HashMap();
		result.put(MyAction.STATUS, MyAction.ERROR);
		result.put(MyAction.MESSAGE, message);
		return result;
	}
	
	
	/***
	 * 根据字典表表名编号获取相关的字典数据
	 * @param codeId 字典表表名编号 
	 * @return 字典数据
	 */
	public Map getCodeMap(String codeId){
		return new HashMap(this.getReaderCacheData().getCodeMap(codeId));
	}
	
	/**
	 * 将form中修改的属性复制到目标对象中，进复制在form中有提交的属性。
	 * copyUpdatedProperties
	 * @param formAttr source在form中的属性名
	 * @param source 从form的属性中获取的对象信息，一般通过嵌套属性从前台获取值
	 * @param target 目标对象，一般为从数据库中查询的持久化对象。
	 */
	public void copyUpdatedProperties(String formAttr,Object source,Object target){
	    String[] updateProps = context.getUpdateProperties(formAttr);
	    for (String prop:updateProps){
            if(prop.indexOf(".")>0){
                prop=prop.substring(0, prop.indexOf("."));
            }
            Object value = null;
	        try {
	            Method getMethod = source.getClass().getMethod("get"+StringUtils.capitalize(prop));
	            value = getMethod.invoke(source);
            } catch (Exception e) {
                //尝试通过field访问
                try {
                    Field field = source.getClass().getField(prop);
                    value = field.get(source);
                } catch (Exception e1) {
                    logger.info("复制属性获取原值出错:"+prop);
                    e1.printStackTrace();
                } 
            }
            try {
                BeanUtils.setProperty(target, prop, value);
            } catch (Exception e) {
                logger.info("复制属性出错:"+prop);
                e.printStackTrace();
            }
	    }
	}
    /**
     * ACTION默认执行方法
     * execute
     * @return 分发路径或者需要转化为AJAX的协议说明
     * 返回的JSON数据中，原集合类的表示为数组，对象以及Map类表示为对象，字符串表示为字符串，数字表示为数字。
     * 分发路径在struts-config中配置
     * AJAX协议说明:
     * 格式: AJAX:attributeName1,attributeName2[,....]
     * 说明：以"AJAX:"开头，后跟多个需要转成AJAX的属性名。
     * 
     * @return 分发路径或者需要转换为AJAX的对象
     */
    public String execute() {
        return SUCCESS;
    }

    /**
     * 校验方法
     * 
     */
    public void validate() {
    }

    /**
     * setContext 注入上下文对象
     * 
     * @param context
     *            上下文对象
     * 
     */
    public void setContext(MyContext context) {
        this.context = context;
    }

    public MyContext getContext() {
        return context;
    }

    /**
     * addActionError 添加特定的错误信息
     * 
     * @param key
     *            错误key，如对应input的name，可以用于按字段输出错误信息
     * @param errorMessage
     *            errorMessage
     * 
     */
    public void addActionError(String key, String errorMessage) {
        actionErrors.put(key, errorMessage);
    }

    /**
     * addActionError 添加普通错误信息
     * 
     * @param errorMessage
     *            errorMessage
     * 
     */
    public void setActionError(String errorMessage) {
        this.actionError = errorMessage;
    }

    /**
     * getActionErrors
     * 
     * @return 特定错误信息Map
     * 
     */
    public Map getActionErrors() {
        return actionErrors;
    }

    /**
     * getActionError 获取特定的错误信息
     * 
     * @param key
     *            错误信息存放的key
     * @return 错误信息
     * 
     */
    public String getActionError(String key) {
        return (String) actionErrors.get(key);
    }

    /**
     * getActionError 获取普通错误信息
     * 
     * @return actionError
     * 
     */
    public String getActionError() {
        return actionError;
    }

    /**
     * hasActionError 判断是否有错误信息
     * 
     * @return 有则返回true,否则false
     * 
     */
    public boolean hasActionError() {
        return (actionError == null || actionError.equals("")) && (actionErrors == null || actionErrors.isEmpty());
    }

    
    /**
     * 判断字符串是否为空
     * 
     * @param obj
     *            obj
     * @return boolean
     */
    public boolean isEmpty(String obj) {
        return obj == null || obj.equals("");
    }

    /**
     * 判断字符串是否为空
     * 
     * @param obj
     *            obj
     * @return boolean
     */
    public boolean notEmpty(String obj) {
        return !isEmpty(obj);
    }

    /**
     * 空值替换
     * 
     * @param obj
     *            obj
     * @param value
     *            value
     * @return String
     * @author:
     */
    public String nvl(String obj, String value) {
        if (isEmpty(obj)) {
            return value;
        }
        return obj;
    }

    /**
     * 空值替换
     * 
     * @param obj
     *            obj
     * @param value
     *            value
     * @return Integer
     * @author:
     */
    public Integer nvl(Integer obj, Integer value) {
        if (obj == null) {
            return value;
        }
        return obj;
    }

    /**
     * getPageInfo
     * 
     * @return PageInfo
     * 
     */
    public PageInfo getPageInfo() {
        return pageInfo;
    }

    public void setPageInfo(PageInfo pageInfo) {
        this.pageInfo = pageInfo;
    }

    public MyInterceptorStack getInterceptorStack() {
        return interceptorStack;
    }

    /**
     * setInterceptorStack
     * 此类中为默认的拦截栈，如果已经存在则不覆盖
     * @param interceptorStack interceptorStack
     * 
     */
    public void setInterceptorStack(MyInterceptorStack interceptorStack) {
        if(this.interceptorStack==null){
            this.interceptorStack = interceptorStack;
        }
    }


	/**
	 * 初始化form
	 * @param mapping
	 * @param request
	 * 
	 */
	public void reset(ActionMapping mapping, HttpServletRequest request) {
	    
	    //获取提交的数据，自动初始化嵌套提交属性为相应类型的Object    
	    Enumeration pNames = request.getParameterNames();
        List<String> updateProps=new ArrayList<String>();
        Set<String> autoInitProps = new HashSet();
        while (pNames.hasMoreElements()){
            String pName = (String) pNames.nextElement();
            String pValue = request.getParameter(pName);
            //仅处理含嵌套属性的对象，且不能是索引类型属性
            if(pName.contains(".") && !pName.contains("[")){
                autoInitProps.add(pName.substring(0,pName.lastIndexOf(".")));
            }
        }
        for(String prop:autoInitProps){
            try {
                autoInitProp(this,prop);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
	
    /**
     * autoInitProp
     * @param prop
     * 
     * @throws NoSuchMethodException 
     * @throws SecurityException 
     * @throws InvocationTargetException 
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     * @throws InstantiationException 
     */
    private void autoInitProp(Object object,String prop) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String curentProp = prop;
        Integer index = null;
        if(prop.indexOf(".")>0){
            curentProp = prop.substring(0,prop.indexOf("."));
        }
        
        String methodName = "get"+StringUtils.capitalize(curentProp);
        Method getter = object.getClass().getMethod(methodName);
        Class type = getter.getReturnType();
        Method setter = object.getClass().getMethod("set"+StringUtils.capitalize(curentProp), type);
        Object fieldValue = getter.invoke(object);
        //获取包名的前缀
//    	String packagePrefix=MyWebContextLoader.getInstance().getPackageNamePrefix();
        if (!type.isPrimitive() && !type.isArray() && !type.isInterface()) {// && type.getPackage().getName().indexOf(packagePrefix) == 0 
            if(fieldValue==null){
                fieldValue = type.newInstance();
                logger.info("自动初始化属性:"+object.getClass().getName()+"."+prop);
                setter.invoke(object, fieldValue);
            }
            if(prop.indexOf(".")>0){
                autoInitProp(fieldValue,prop.substring(prop.indexOf(".")+1));
            }
        }
    }
    /**
     * 连接请求参数串
     * getParamStr
     * @return 参数串
     * 
     */
    public String getParamStr(String excludeParams){
        StringBuffer paramsStr= new StringBuffer();
        String excludeParamStr = ","+excludeParams+",";
        Enumeration<String> paramNames = context.getParameterNames();
        if(paramNames!=null){
            while (paramNames.hasMoreElements()){
                String pName = paramNames.nextElement();
                if(excludeParamStr.contains(","+pName+",")){
                    continue;
                }
                if(paramsStr.length()>0){
                    paramsStr.append("&");
                }
                paramsStr.append(pName).append("=").append(context.getParameter(pName));
            }
        }
        return paramsStr.toString();
    }
	public ReaderCacheData getReaderCacheData() {
		return readerCacheData;
	}
	public void setReaderCacheData(ReaderCacheData readerCacheData) {
		this.readerCacheData = readerCacheData;
	}
    
}
